Home | Rules | Authors | Mailing lists | Menus and hot keys | Network game | Command line parameters | Platform specific issues | User levels | Core algorithm | Source code | Bugs | To do | Copying

Source code


General remarks

Modularity

Liquid War 5 is basically a big C program. I've splitted the source code in many small files for I do not like to have to handle big monolithic sources, but this does not mean Liquid War is very modular. In fact Liquid War 5 is quite bloated with global variables and other ugly stuff 8-(

Coding style

To be honest, it's a big mess. You won't find 2 files coded in the same maner... OK, I'm exagerating a bit. From now I try to make an effort and stick to basic rules such as:

I might decide to rename and cleanup everything some day, for it would help other coders to understand what I wrote, but well, this is certainly not a thrilling task 8-/


Source files organization

Main game code

Here you'll find the main() function, the main game loop, application-wide constants and other global stuff.

It might be a good start if you want to hack the code.

Menus

The menus are coded using the Allegro GUI system. While this system is very powerfull, it's IMHO not adapted to very complex GUIs, and one of its drawbacks is that it's not so easy to redesign something once you've coded it.

Besides, when I started coding the GUI in 1998, I did it in a rather ugly way, and now I'm paying for my being lazy at that time, since I spent hours coding when I want to change something 8-/

GUI tools

These files contain various utilities which are used in the menus.

Core algorithm

Here's *the* interesting part. All the rest of the code is just sugar coat to display stuff, receive players commands, communicate with other computers, handle errors, etc... But the real thing is here!

It's funny to note that these files have almost not been modified since Liquid War 5.0.

It's also interesting to note that they represent a small percentage of the total amount of code in the game. This tends to prove - and I'm convinced of it - that game programming does not only consists in having great ideas, but also requires a lot of "dirty" and boring work. Honestly, coding an option menu is as boring as coding Liquid War algorithm is fun.

Moving cursors

It looks like nothing, but moving a cursor and deciding where it should go if there's a wall in front of it is not that easy, especially if you want things to work nicely.

User input

Until 5.4.0, Liquid War did not have network support. As it is designed to be multiplayer, one needed to have several players on the same computer. The mouse also needed to be handled in a special way since cursors can *not* pass walls in Liquid War. Additionnally, I wanted all input channels (keyboard mouse and joystick) to be handled in a unified way.

This explains why there's so much code for user input, when one would think at first sight that "polling the keyboard is enough".

Initialisations

These files contain functions to intialize various game components. 100% boring code.

Graphics

Here lies most of the graphic functions in Liquid War. There's not that much code since Liquid War's strength is not its visual effects, but rather its gameplay.

The only "funny" thing is the wave effect. I'm quite happy with it, and honestly, I do think it is rather fast, given the fact that it uses no 3D hardware at all.

Sound and music

Sound and music routines required some encapsulation, since the game must be able to run even if the sound and/or music did not load correctly.

Data management

These functions handle the datafile contents and also the custom data.

Note that the various utilities such as liquidwarcol, liquidwarmap and liquidwartex do not share code with the main executable. This is obviously a design error, for liquidwarmap will handle maps in a very poor way and is unable to autodetect map errors, whereas the game does it rather well. Blame the programmer.

Random map generator

Liquid War has a "generate random map" feature which is available within the game and also as an external program. The source code for the external program is in ./utils/lwmapgen in Liquid War source distribution. This program has been coded by David Redick, is also available on www.cs.clemson.edu/~dredick/lwmapgen/ and works on GNU/Linux. Compiling this program under DOS and/or Windows is untested and unsupported.

The random map generator within Liquid War - which of course works on any platform support by LW - uses for its greater part the same source code as the external lwmapgen program.

Time handling

Time handling is fundamental in a game. Time is used for visual effects (waves...) during the game, it's used to generate some pseudo random stuff, well, it's used everywhere!

Note that on the client, I use 2 "different" clocks. The first counts the "real" time, in seconds. The second one is counts "rounds" and is incremented by 1 at each game round.

In-game utilities

These are various utilities use to monitor and control the game while one's playing.

Command line handling

OK, now to all the UNIX guys, I *know* there are many ways to do things in a better and simple way than I did. But keep in mind that in 1998, under DOS, I had a rotten command line and even now I need everything to work on both UNIX and Microsoft platforms.

These utilities are not perfect, but they work, that's all I ask them.

Locale support

Liquid War now has locale support. Basically, all the labels and texts in the UI are stored in constants. There's simply file per language.

Note to translators: if you decide to translate the menus in another language, keep in mind that all the translations must fit in the various buttons and textboxes. The best resolution to test this - the one where letters take most place - is 640x480.

Log and various messages

OK, the API of the log routines is a piece of crap. Now I'm simply too lazy to change it. It works, that's all I ask.

BTW, there's a clear advantage in using custom-made log functions instead of plain calls to "fprintf(stderr,...". It might not be obvious for UNIX users, but think about Windows. Nothing like a "tail -f" there, nor a proper output redirection system. When a user clicks on the Liquid War icon, I want "console" information to be logged in a file!

Macros, utilities and string support

As usual, I needed to prepare a small set of usefull macros.

It's also important to note that Liquid War uses snprintf instead of sprintf, for using the latter is very likely to cause buffer overflows. Under Linux glibc provides this function but Microsoft does not provide it natively on Windows. Therefore I used a third party snprintf implementation by Mark Martinec: www.ijs.si/software/snprintf/ and its source is available in the ./utils directory of Liquid War source distribution.

Byte order and endianess

As you might know, PC Intel based computers are "little-endian" while Sun Sparc stations and Mac computers are "big-endian". This is an issue for LW since in network games maps are transmitted in binary format. Therefore I needed to set up some (un)serialization fonctions.

Thread support

Liquid War does have thread support, but it is a "limited" thread support. I mean that the game is generally monothreaded, but a few functions use threads. For instance, calls to the meta-server are done within threads.

Basically, I do not really enjoy programming in a multithreaded environnement. So when possible, I chose the monothread path, and used threads only where I simply would not be able to find another acceptable solution.

I also needed to use some mutexes to prevent crashes in the user interface.

Launching external programs

Liquid War might sometimes launch external programs. This is (for security reason) not a default behavior and has to be activated and configured by yourself, using the "-callback" command line option on the server for instance.

Low-level network code

There are network packages for Allegro, but I decided not to use them. Socket support is not that hard to implement under UNIX and Win32 and besides, I've done it for my job recently, so I just knew how to do it.

Another reason which decided me to code my own toolbox is that I did not want Liquid War to have external dependencies - except Allegro of course. This way, UNIX gamers to not have to set up and/or download a specific network library. It's also easier to integrate the game in projects like Debian if it has few dependencies.

This network code is not a masterpiece, it's just a little set of tools that have proven to work. That's all.

BTW, it's important to notice that when linking with Allegro, most blocking UNIX calls ("sleep" or "recv" for instance) stop working: they alwasys return immediately. This led me to implement weird ugly hacks, like calling "recv" in a loop until it gets what it wants... This is theorically and practically a performance killer, but I found no other way to fix this. And FYI, this is not an Allegro bug, it's a feature 8-)

High-level network code

These files contains network utilities which are Liquid War specific.

Communication with the meta-server

The meta-server is called by both client and server. Basically, the server registers itself, and the client asks for a list of servers.

The meta-server itself is just a set of simple PHP scripts with a simple MySQL database. I chose PHP because my provider allows execution of PHP pages, that's all.

The protocol is *very* basic, and uses HTTP 1.0 for requests. Answers are received in plain text, with one information per line. There's no garantee that this would work with any HTTP server, but experience proved that it works with my provider 8-)

Server code

The Liquid War server is a rather small program. The only thing it does is accept new players, transmit map and game parameters between them, and then "replicate keys".

By "replicate keys" I mean that the server asks each client what keys have been pressed during the last round, and then dispatches this informations to all clients. This implies that the server has absolutely no idea of who's loosing, who's winning, etc...

All the "logic" of the server is coded in these files, the rest is only utilities and helper functions.


This documentation is also available on: www.ufoot.org/liquidwar.